package com.tom.learnhigher.aiservices;

import com.tom.contants.Contants;
import com.tom.learnbase.two.ChatMemoryTest;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiModelName;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.SystemMessage;
import dev.langchain4j.service.UserMessage;
import dev.langchain4j.service.V;
import org.junit.jupiter.api.Test;

import java.time.Duration;
import java.time.LocalDate;

/**
 * llm驱动的应用程序通常不仅需要单个组件，还需要多个组件一起工作 (例如，提示模板，聊天内存，llm，输出解析器，RAG组件:嵌入模型和存储) 并且通常涉及多个交互
 * 目前在LangChain4j中有两个高级概念可以帮助实现这一点:AI服务和链。
 * AI Services 人工智能服务
 *
 * 为Java量身定制。 其想法是隐藏与llm和其他组件交互的复杂性，隐藏在一个简单的API后面。
 * 这种方法非常类似于Spring Data JPA或Retrofit:你声明式地定义一个带有所需API的接口， 而LangChain4j提供了一个对象(代理)来实现这个接口。 您可以将AI Service视为应用程序中服务层的一个组件。 它提供人工智能服务。因此得名。
 *
 * AI Services  常见的操作：
 * 格式化LLM的输入
 * 格式化LLM的输入
 * Chat memory
 * Tools
 * RAG
 *
 *
 */
public class AIServicesTest {


    interface Assistant {

        String chat(String message);
    }
    /**
     * 最简单的示例
     *
     * 原理
     * 您将接口的 Class 与底层组件一起提供给 AiServices
     * AiServices 创建一个实现该接口的代理对象。 目前，它使用反射，但我们也在考虑替代方案。 这个代理对象处理输入和输出的所有转换。
     * 在本例中，输入是单个 String ，但是我们使用的是 ChatLanguageModel ，它接受 ChatMessage 作为输入。 因此， AiService 将自动将其转换为 UserMessage 并调用 ChatLanguageModel 。
     * 由于 chat 方法的输出类型是 String ，因此在 ChatLanguageModel 之后返回 AiMessage ， 在从 chat 方法返回之前，它将被转换为 String 。
     *
     *
     */
    @Test
    public void SimplestAIServiceTest(){
        Assistant assistant = AiServices.create(Assistant.class,Contants.openAiChatModel);

        String answer = assistant.chat("Hello! My name is Klaus.");
        System.out.println(answer); // Hello Klaus! How can I assist you today?

        String answerWithName = assistant.chat("What is my name?");
        System.out.println(answerWithName); // Your name is Klaus.

    }



    interface Friend {

        @SystemMessage("You are a good friend of mine. Answer using slang.")
        String chat(String userMessage);
    }

    /**
     * @SystemMessage 标签作用，设置默认会话中llms的角色和功能
     *
     */
    @Test
    public void SystemMessageTest(){
        Friend friend = AiServices.create(Friend.class, Contants.openAiChatModel);

        String answer = friend.chat("Hello"); // Hey! What's up?
        System.out.println(answer);
    }



    interface Friend2 {

        @UserMessage("You are a good friend of mine. Answer using slang. {{it}}")
        String chat(String userMessage);

        @UserMessage("You are a good friend of mine. Answer using slang. {{it}}")
        String chat2(@V("it") String userMessage);//绑定参数写法
    }


    /**
     * @UserMessage 格式化用户输入内容
     *
     */
    @Test
    public void UserMessageTest(){
        Friend2 friend = AiServices.create(Friend2.class, Contants.openAiChatModel);

        String answer = friend.chat("Hello"); // Hey! What's up?
        System.out.println(answer);
    }







    enum Sentiment {
        POSITIVE, NEUTRAL, NEGATIVE
    }

    interface SentimentAnalyzer {

        @UserMessage("Analyze sentiment of {{it}}")
        Sentiment analyzeSentimentOf(String text);

        @UserMessage("Does {{it}} has a positive sentiment?")
        boolean isPositive(String text);
    }


    /**
     * 格式化输出内容
     */
    @Test
    public void formatResp(){
        SentimentAnalyzer sentimentAnalyzer = AiServices.create(SentimentAnalyzer.class, Contants.openAiChatModel);

        Sentiment sentiment = sentimentAnalyzer.analyzeSentimentOf("This is great!");
        // POSITIVE
        System.out.println(sentiment);

        boolean positive = sentimentAnalyzer.isPositive("It's awful!");
        // false
        System.out.println(positive);
    }



    class Person {
        String firstName;
        String lastName;
        LocalDate birthDate;
        Address address;
    }

    class Address {
        String street;
        Integer streetNumber;
        String city;
    }

    interface PersonExtractor {

        @UserMessage("Extract information about a person from {{it}}")
        Person extractPersonFrom(String text);
    }


    /**
     * 格式化输出内容 为自定义类
     */
    @Test
    public void formatResp2POJO(){

        OpenAiChatModel model = OpenAiChatModel.builder()
                .apiKey(Contants.key)
                .modelName(OpenAiModelName.GPT_3_5_TURBO)
                .temperature(0.3)
                .timeout(Duration.ofSeconds(60))//60秒
                .logRequests(true)
                .logResponses(true)
                .build();

        PersonExtractor personExtractor = AiServices.create(PersonExtractor.class, model);

        String text ="""
            In 1968, amidst the fading echoes of Independence Day,
            a child named John arrived under the calm evening sky.
            This newborn, bearing the surname Doe, marked the start of a new journey.
            He was welcomed into the world at 345 Whispering Pines Avenue
            a quaint street nestled in the heart of Springfield
            an abode that echoed with the gentle hum of suburban dreams and aspirations.
            """;

        Person person = personExtractor.extractPersonFrom(text);

        System.out.println(person); // // Person { firstName = "John", lastName = "Doe", birthDate = 1968-07-04, address = Address { ... } }
    }


    /**
     * JSON mode JSON模式
     */
    @Test
    public void JsonTest(){
        OpenAiChatModel chatModel = OpenAiChatModel.builder().apiKey(Contants.key)
                .responseFormat("json_object")
                .build();
        String ss="Extract information about a person from ";
        ss+="""
                In 1968, amidst the fading echoes of Independence Day,
            a child named John arrived under the calm evening sky.
            This newborn, bearing the surname Doe, marked the start of a new journey.
            He was welcomed into the world at 345 Whispering Pines Avenue
            a quaint street nestled in the heart of Springfield
            an abode that echoed with the gentle hum of suburban dreams and aspirations.
                """;
        String generate = chatModel.generate(ss);
        System.out.println(generate);

    }


    //other-examples/src/main/java/OtherServiceExamples.java 官方示例





}
